#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <sys/wait.h>
#include <string.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#define MAX 1024
#define ARGC 64
#define SEP " "
enum re_dir
{
  NONE_DIR=-1,
  RIGHT_DIR =1,
  RRIGHT_DIR =2,
  LEFT_DIR =0
};
void split(char* commandstr,char* str[])
{
  assert(commandstr);
  assert(str);

  str[0] = strtok(commandstr,SEP);
  int i=1;
  while(str[i++] = strtok(NULL,SEP))
  {
    ;
  }
}

void debugPrint(char* str[])
{
  for(int i=0;i<ARGC;i++)
  {
    if(str[i] == NULL)
    {
      break;
    }
    printf("%s ",str[i]);
  }
  printf("\n");
}
int check_redir(char* str[],int* x)
{
  int i=0;
  while(str[i])
  {
    if(strcmp(str[i],">") == 0)
    {
      *x = RIGHT_DIR;
      return i;
      break;
    }
    if(strcmp(str[i],">>") == 0)
    {
      *x= RRIGHT_DIR;
      return i;
      break;
    }
    if(strcmp(str[i++],"<") == 0)
    {
      *x = LEFT_DIR;
      return i;
      break;
    }
  }
  i=0;
  *x = NONE_DIR;
  return i;
}
void showenv()
{
  extern char** environ;
  for(int i=0;environ[i];i++)
  {
    printf("%d %s\n",i,environ[i]);
  }
}
void ch_dup2(int  buf_r,int index,char* str[])
{
  int target = 0;
  if(buf_r == RIGHT_DIR)
  {
   target =  open(str[index+1],O_WRONLY | O_CREAT | O_TRUNC,0666);
  }
  else if(buf_r == RRIGHT_DIR)
  {
   target =  open(str[index+1],O_WRONLY | O_CREAT | O_APPEND,0666);
   dup2(target,buf_r-1);
   return;
  }
  else if(buf_r == LEFT_DIR)
  {
    target =open(str[index+1],O_RDONLY);
  }
  dup2(target,buf_r);
}
int main()
{
  int zt=-1;
  char my_enuv[32][128] = {NULL};
  int enuv_pos =0;
  int m_status=0;
  while(1)
  {
    char commandstr[MAX] = {0};
    char* str[ARGC] = {NULL};
    printf("[wdf@myshell currpath]# ");
    fflush(stdout);
    char* warning = fgets(commandstr,sizeof(commandstr),stdin);
    commandstr[strlen(commandstr)-1] = 0;
    assert(warning);
    split(commandstr,str);
    if(strcmp(str[0],"ls") == 0)
    {
      int pos =0;
      while(str[pos])
      {
        pos++;
      }
      str[pos++] = (char*)"--color=auto";
    }
    else if(strcmp(str[0],"cd") == 0 && str[1] != NULL)
    {
      chdir(str[1]);
      continue;
    }
    else if(strcmp(str[0],"env")== 0)
    {
      showenv();
      continue;
    }
    else if(strcmp(str[0],"echo") == 0 && *str[1] == '$')
    {
      const char* target_env = NULL;
      target_env = getenv(str[1]+1);
      if(*(str[1]+1) == '?') printf("%d\n",m_status);
      else if(target_env != NULL ) printf("%s=%s\n",str[1]+1,target_env);
      continue;
    }
    if(strcmp(str[0],"export") == 0 && str[1] != NULL)
    {
      strcpy(my_enuv[enuv_pos],str[1]);
      putenv(my_enuv[enuv_pos++]);
      continue;
    }
    
    pid_t child = fork();
    if(child == 0)
    {
      int redir_index= check_redir(str,&zt);
      if(zt >= 0)
      {
        ch_dup2(zt,redir_index,str);
        str[1] = NULL;
      }
      execvp(str[0],str);
      exit(1);
    }
    waitpid(child,&m_status,0);
    if(m_status > 0)
    {
      m_status = WEXITSTATUS(m_status);
    }
  } 
  return 0;
}
